package com.qubi.exchange.rest;

import cn.hutool.core.util.StrUtil;
import com.alicp.jetcache.anno.CacheType;
import com.alicp.jetcache.anno.Cached;
import com.qubi.exchange.biz.ColaExchangeBiz;
import com.qubi.exchange.biz.ColaSymbolBiz;
import com.qubi.exchange.biz.CommonExchangeBiz;
import com.qubi.exchange.constant.OrderDirection;
import com.qubi.exchange.constant.OrderStatus;
import com.qubi.exchange.constant.OrderType;
import com.qubi.exchange.data.MarketInfo;
import com.qubi.exchange.data.MakeOrderParams;
import com.qubi.exchange.dto.ColaUserBalanceVo;
import com.qubi.exchange.message.OrderMessage;
import com.qubi.exchange.mapper.OrderMapper;
import com.qubi.exchange.queue.LinkedBlockingQueueMap;
import com.qubi.exchange.security.auth.client.annotation.IgnoreClientToken;
import com.qubi.exchange.security.auth.client.annotation.IgnoreUserToken;
import com.qubi.exchange.security.auth.client.config.UserAuthConfig;
import com.qubi.exchange.security.auth.client.i18n.ColaLanguage;
import com.qubi.exchange.security.auth.client.jwt.UserAuthUtil;
import com.qubi.exchange.security.common.constant.ResponseCode;
import com.qubi.exchange.security.common.context.BaseContextHandler;
import com.qubi.exchange.security.common.msg.AppResponse;
import com.qubi.exchange.security.common.msg.TableResultResponse;
import com.qubi.exchange.service.AccountService;
import com.qubi.exchange.service.KlineService;
import com.qubi.exchange.service.MatchService;
import com.qubi.exchange.util.InFluxDbService;
import com.qubi.exchange.util.Snowflake;
import com.qubi.exchange.websocket.OrderNotifyEntity;
import com.qubi.me.entity.ColaCoinSymbol;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @author wx
 * @create 2019-02-16 11:53
 **/
@Log4j2
@RestController
@IgnoreClientToken
public class ColaExchangeController {

    @Resource(name = "matchOrderQueue")
    LinkedBlockingQueueMap<OrderMessage> matchOrderQueue;

    @Autowired
    ColaExchangeBiz biz;

    @Autowired
    MatchService service;

    @Autowired
    InFluxDbService inFluxDbService;

    @Autowired
    OrderMapper orderMapper;

    @Autowired
    AccountService accountService;

    @Autowired
    ColaSymbolBiz symbolBiz;




    @Autowired
    UserAuthUtil userAuthUtil;

    @Autowired
    UserAuthConfig userAuthConfig;

    @Autowired
    KlineService klineService;

    @Autowired
    CommonExchangeBiz exchangeBiz;


    private Snowflake snowflake = new Snowflake();
    private AtomicInteger makeOrderCount = new AtomicInteger(0);

    private BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(12);
    public static long  startTime=System.currentTimeMillis();

    /**
     * k 线
     *
     * @param pair  交易对
     * @param end   返回这个时间点以前的指定条数,不传则默认是当前
     * @param limit 条数,最大默认 2000
     * @param type  类型
     * @return
     */
    @RequestMapping("kline")
    public AppResponse kline(String pair, Long start, Long end, Integer limit, String type, String code) {
        return exchangeBiz.getKlines(pair, start, end, limit, type, code);
    }

    /**
     * 深度
     *
     * @return
     */
    @RequestMapping("depth")
    @Cached(name = "depth", expire = 2, cacheType = CacheType.LOCAL)
    @IgnoreUserToken
    public AppResponse depth(String pair, Integer length, Integer scale,String userId) {
        if (StringUtils.isBlank(pair)) {
            return AppResponse.paramsError();
        }

        return exchangeBiz.getDepthData(pair, length, scale);
    }



    /**
     * 获取市场行情
     *
     * @return
     */
    @RequestMapping("market")
    public AppResponse market(HttpServletRequest request, String pair, String symbol, Integer onlyFav) {
        String userId = "-1";

        if (onlyFav != null && onlyFav == 1) {
            return AppResponse.ok().data(biz.getMarketByFav(userId));
        }
        if (StringUtils.isNotBlank(pair)) {
            MarketInfo data = biz.getMarketByPair(pair, userId);
            return AppResponse.ok().data(data);
        }
        if (StringUtils.isNotBlank(symbol)) {
            List<MarketInfo> data = biz.getMarketBySymbol(symbol, userId);
            return AppResponse.ok().data(data);
        }
        List<Map<String, Object>> list = biz.getMarketAllByUser(userId);
        return AppResponse.ok().data(list);
    }

    /**
     * 获取市场行情
     *
     * @return
     */
    @RequestMapping("marketAll")
    public AppResponse marketAll(HttpServletRequest request) {

        List<String> symbols = symbolBiz.getSymbols();
        List<MarketInfo> list = new ArrayList<>();
        for (String symbol : symbols) {
            list.addAll(biz.getMarketBySymbol(symbol, null));
        }
        return AppResponse.ok().data(list);
    }

    /**
     * 获取市场行情
     *
     * @return
     */
    @RequestMapping("marketByPair")
    public AppResponse market(HttpServletRequest request, String pair) {
        String userId = "-1";

        if (StringUtils.isNotBlank(pair)) {
            MarketInfo data = biz.getMarketByPair(pair, userId);
            return AppResponse.ok().data(data);
        }
        return AppResponse.paramsError();
    }


    /**
     * 48小时趋势
     *
     * @param pair
     * @return
     */
    @RequestMapping(value = "/getTendency", method = RequestMethod.GET)
    @Cached(cacheType = CacheType.LOCAL, expire = 10)
    public AppResponse getTendency(String pair) {
        List<Number> numbers = inFluxDbService.getTendency(pair);
        return AppResponse.ok().data(numbers);
    }

    /**
     * 48小时趋势
     *
     * @param pairs
     * @return
     */
    @RequestMapping(value = "/getTendencies", method = RequestMethod.POST)
    @Cached(cacheType = CacheType.LOCAL, expire = 10)
    public AppResponse getTendencies(@RequestBody List<String> pairs) {
        Map<String, List<Number>> tendencyMap = new HashMap<>();
        pairs.forEach(x -> {
            List<Number> numbers = inFluxDbService.getTendency(x);
            tendencyMap.put(x, numbers);
        });
        return AppResponse.ok().data(tendencyMap);
    }

    /**
     * 获得交易token
     *
     * @return
     */
    @RequestMapping(value = "getTransactionSign", method = RequestMethod.POST)
    public AppResponse<HashMap> getTransactionSign(@RequestBody Map<String, String> params) {
        String token = BaseContextHandler.getToken();
        String sign = UUID.randomUUID().toString();
        String userId = BaseContextHandler.getUserID();
        String moneyPassword_real = biz.getUserMoneyPassword(userId);
        if (moneyPassword_real == null)
            return new AppResponse(ResponseCode.NO_MONEY_PASSWORD_CODE, ResponseCode.NO_MONEY_PASSWORD_MESSAGE);

        if (encoder.matches(params.get("pin"), moneyPassword_real)) {
            biz.setSign(sign, token);
            var data = new HashMap<String, Object>(2);
            data.put("token", sign);
            data.put("expire", (25 - 1) * 60 * 60 * 1000);
            return AppResponse.ok().data(data);
        } else {
            return new AppResponse(ResponseCode.PIN_ERROR_CODE, ResponseCode.PIN_ERROR_MESSAGE);
        }

    }



    /**
     * 下单
     *
     * @param
     * @return
     */
    @RequestMapping(value = "makeOrder", method = RequestMethod.POST)
    public AppResponse makeOrder(@RequestBody MakeOrderParams makeOrderParams) {
        return exchangeBiz.placeOrder(makeOrderParams);
    }


    /**
     * 取消订单
     *
     * @param params
     * @return
     */
    @RequestMapping(value = "cancelOrder", method = RequestMethod.POST)
    public AppResponse cancelOrder(@RequestBody Map<String, String> params) {

        return exchangeBiz.doCancel(params);
    }


    /**
     * 获得市场订单(查询数据库即可)
     *
     * @return
     */
    @RequestMapping("getMarketOrder")
    @Cached(cacheType = CacheType.LOCAL,expire = 3)
    public AppResponse getMarketOrder(String pair, Integer size) {
        if (size == null || size == 0) {
            size = 20;
        }
        List<OrderNotifyEntity> list = biz.getMarketOrder(pair, size);
        return AppResponse.ok().data(list);
    }

    /**
     * 查询数据库即可
     *
     * @return 返回交易和交易明细
     */
    @RequestMapping("getPersonOrder")
    public AppResponse getPersonOrder(String pair, Long timestamp, Integer size, String type, Integer isPending) {
        List<OrderMessage> list = exchangeBiz.getOrderMessages(pair, timestamp, size, type, isPending);
        return AppResponse.ok().data(list);
    }



    /**
     * 查询数据库即可
     *
     * @return 返回交易和交易明细
     */
    @RequestMapping("getPersonOrderDetail")
    public AppResponse getPersonOrderDetail(String orderId) {
        Map<String, Object> list = biz.getPersonOrderDetail(orderId);
        return AppResponse.ok().data(list);
    }


    /**
     * 查询数据库即可
     *
     * @return
     */
    @RequestMapping("orderManagement")
    public TableResultResponse orderManagement(String pair, String state, Integer page, Integer size, String type,
                                               Long startTime, Long endTime, String pairL, String pairR,String isPending) {
        String userId = BaseContextHandler.getUserID();
        if (page == null || page == 0) {
            page = 1;
        }
        if (size == null || size == 0) {
            size = 10;
        }
        return biz.orderManagement(userId, pair, state, page, size, type, startTime, endTime, pairL, pairR,isPending);
    }

    /**
     * 获得交易对余额
     *
     * @param pair
     * @return
     */
    @RequestMapping("getBalance")
    public AppResponse getBalance(String pair, String coinCode) {
        ColaUserBalanceVo[] balanceVos = biz.getBalance(pair, coinCode);
        return AppResponse.ok().data(balanceVos);
    }
    @RequestMapping("getBalanceList")
    public AppResponse getBalanceList() {
        var balanceVos = biz.getAllUserBalance(BaseContextHandler.getUserID());
        return AppResponse.ok().data(balanceVos);
    }

    /**
     * 获得交易对或者币种的价格
     *
     * @param coinCode
     * @param pair
     * @return
     */
    @RequestMapping("getCoinPrice")
    @Cached(name = "coinPrice", cacheType = CacheType.LOCAL, expire = 10)
    public AppResponse getCoinPrice(String coinCode, String pair) {
        if (StringUtils.isNotBlank(coinCode)) {
            BigDecimal price = biz.getCoinPrice(coinCode);
            return AppResponse.ok().data(price);
        } else if (StringUtils.isNotBlank(pair)) {
            return AppResponse.ok().data(biz.getPairPrice(pair));
        }
        return AppResponse.paramsError();
    }


    /**
     * 新开一个交易对
     *
     * @param params
     * @return
     */
    @RequestMapping("/admin/addPair")
    public boolean addPair(@RequestBody Map<String, Object> params) {
        String pair = StrUtil.toString(params.get("pair"));
        if (StringUtils.isBlank(pair)) return false;
        return biz.addPair(pair);
    }

    private boolean assertGreaterThanZero(BigDecimal amount) {
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            return false;
        }
        return true;
    }


    public static AtomicLong count = new AtomicLong(0);
    private long rate = 0;

    @RequestMapping("getTps")
    public AppResponse getTps() {
        return AppResponse.ok().data(rate);
    }

    @Scheduled(cron = "*/1 * * * * ?")
    public void countTps() {
        rate = count.get();
        count.set(0);
    }
    @RequestMapping(value = "getPairs",method = RequestMethod.GET)
    @Cached(name = "coinPrice", cacheType = CacheType.LOCAL, expire = 10)
    public AppResponse getPairs()
    {
        return AppResponse.ok().data( symbolBiz.getCoinSymbolBySymbol(null));


    }
    @RequestMapping("getAllBalance")
    public AppResponse getAllBalance()
    {
        String userId = BaseContextHandler.getUserID();

        return AppResponse.ok().data(biz.getAllUserBalance(userId));

    }
    @RequestMapping("getCoinDescr")
    public AppResponse getCoinDescr(String coinCode)
    {
        return AppResponse.ok().data(symbolBiz.getCoinDescr(coinCode));
    }
}
